/*
 * Copyright (c) 2011 Obix Labs Limited
 * Redistribution and use in source and binary forms, 
 * with or without modification, are permitted provided 
 * that the following conditions are met:
 * 
 * 		Redistribution of source code must retain the above 
 * 		copyright notice, this list of conditions and the 
 * 		following disclaimer.
 *
 * 		Redistribution in binary form must reproduce the 
 * 		above copyright notice, this list of conditions 
 * 		and the following disclaimer in the documentation 
 * 		and/or other materials provided with the distribution.
 * 
 * 	THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF 
 * 	ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS 
 * 	AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * 	FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, 
 * 	ARE HEREBY EXCLUDED. OBIX LABS LIMITED ("Obix Labs") AND ITS 
 * 	LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 
 * 	AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR 
 * 	ITS DERIVATIVES. IN NO EVENT WILL Obix Labs OR ITS LICENSORS BE 
 * 	LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, 
 * 	INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 
 * 	DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 
 * 	LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS 
 * 	SOFTWARE, EVEN IF Obix Labs HAS BEEN ADVISED OF THE POSSIBILITY OF 
 * 	SUCH DAMAGES.
 */

package com.obixlabs.commons.xml;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import com.obixlabs.commons.ObixException;
import com.obixlabs.commons.io.ClasspathResourceUtils;
import com.obixlabs.commons.io.ResourceReadUtil;

/**
 * <p>
 * Utility class for obtaining a compiled handle to an 
 * XML schema.
 * </p>
 */
public final class SchemaUtils
{
	
	/**
	 * <p>
	 * Private constructor  to prevent instantiation of utility 
	 * class.
	 * </p>
	 */
	private SchemaUtils(){}
	
	/**
	 * <p>
	 * Returns a compiled reference to the schema at the given 
	 * URI. The URI can either be  a web, file or 
	 * {@link ClasspathResourceUtils#isClasspathURL(String) a classpath} 
	 * URI. 
	 * </p>
	 * 
	 * @param uriSpec	The URI from which to load the schema. This
	 * can either be a web, file or {@link ClasspathResourceUtils#isClasspathURL(String) a classpath}
	 * URI.
	 * 
	 * @param requester	A reference to the client object or class requesting the 
	 * schema. This is typically the object or class from which the method is
	 * called. This parameter is only required for determining the current classloader
	 * where the URI is a 
	 * {@link ClasspathResourceUtils#isClasspathURL(String) classpath URL}.
	 *  
	 * @return	A compiled reference to the schema at the given location.
	 * @throws ObixException	If an error occurs loading or parsing the schema 
	 * at the given location.  
	 */
	public static Schema readSchemaFromURL(	String uriSpec,
																									Object requester) 
																									throws ObixException
	{
		Schema result;
		
		byte[] schemaData = 
				ResourceReadUtil.loadResourceData(
										uriSpec, requester);
		result = createSchema(schemaData);
		return result;
	}

	/**
	 * <p>
	 * Parses the given byte array into a compiled XML schema
	 * instance. 
	 * </p>
	 * 
	 * @param data	The data to parse as an XML schema.
	 * @return	A compiled reference to the schema parsed from 
	 * the given byte array.
	 * @throws ObixException	If an error occurs parsing the schema.  
	 */
	public static Schema createSchema(byte[] data) throws ObixException
	{ return createSchema(new ByteArrayInputStream(data)); }

	/**
	 * <p>
	 * Reads and parses an XML schema from the given input stream.
	 * </p>
	 * @param stream	The stream from which to read and parse 
	 * a schema.
	 * @return	A compiled reference to the schema read from the given 
	 * input stream.
	 * @throws ObixException	If an error occurs loading or parsing the schema 
	 * from the given input stream.  
	 */
	public static Schema createSchema(	InputStream stream)
																					throws ObixException
	{
		try {
			return newXSD2001SchemaFactory().newSchema(new StreamSource(stream));
		} catch (SAXException exce) {
			throw new ObixException(exce);
		}
	}

	/**
	 * <p>
	 * Reads the XML schema contained in given file.
	 * </p>
	 * @param file	The file from which to read the XML schema.
	 * @return	A compiled reference to the schema contained within the 
	 * given file.
	 * @throws ObixException	If an error occurs loading or parsing the schema 
	 * from the given file.  
	 */
	public static Schema createSchema(	File file) throws ObixException
	{
		try {
			return newXSD2001SchemaFactory().newSchema(file);
		} catch (SAXException exce) {
			throw new ObixException(exce);
		}
	}

	/**
	 * <p>
	 * Loads a schema from the given URL and returns a 
	 * handle to the compiled schema.
	 * </p>
	 * @param location	The URL from which the schema should be loaded.
	 * @return	A compiled reference to the schema at the given location.
	 * @throws ObixException	If an error occurs loading or parsing the schema 
	 * at the given location.  
	 */
	public static Schema createSchema(	URL location) 
																					throws ObixException
	{
		try {
			return newXSD2001SchemaFactory().newSchema(location);
		} catch (SAXException exce) {
			throw new ObixException(exce);
		}
	}
	
	/**
	 * <p>
	 * Creates a new XML 2001  W3c schema factory, as governed
	 * by the namespace http://www.w3.org/2001/XMLSchema.
	 * </p>
	 * 
	 * @return	An XML 2001  schema factory.
	 */
	public static SchemaFactory newXSD2001SchemaFactory()
	{ return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); }
}